using System;
using System.ComponentModel;
using System.Runtime.Serialization;

namespace SharpGL.SceneGraph.Cameras
{
    /// <summary>
    /// This camera contains the data needed to perform an orthographic transformation
    /// to the projection matrix.
    /// </summary>
    [DataContract()]
    public class OrthographicCamera : Camera
    {
        #region Private Fields

        /// <summary>
        /// The left pos.
        /// </summary>
        [DataMember()]
        private double left = 0.0f;

        /// <summary>
        /// The right pos.
        /// </summary>
        [DataMember()]
        private double right = 1.0f;

        /// <summary>
        /// The top pos.
        /// </summary>
        [DataMember()]
        private double top = 0.0f;

        /// <summary>
        /// The bottom pos.
        /// </summary>
        [DataMember()]
        private double bottom = 1.0f;

        /// <summary>
        /// The near pos.
        /// </summary>
        [DataMember()]
        private double near = 0.0f;

        /// <summary>
        /// The far pos.
        /// </summary>
        [DataMember()]
        private double far = 100.0f;

        #endregion Private Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="OrthographicCamera"/> class.
        /// </summary>
        public OrthographicCamera()
        {
            Name = "Camera (Orthographic)";
        }

        #endregion Constructors

        #region Public Methods

        /// <summary>
        /// This is the main function of the class, to perform a specialised projection
        /// in this case, an orthographic one.
        /// </summary>
        public override void TransformProjectionMatrix(OpenGL gl)
        {
            if (OpenGL.IsValidContext(gl))
            {
                //  Perform the transformation.
                gl.Translate(Position.X, Position.Y, Position.Z);
                gl.Ortho(left, right, bottom, top, near, far);
            }
        }

        #endregion Public Methods

        #region Public Properties

        /// <summary>
        /// Gets or sets the left.
        /// </summary>
        /// <value>
        /// The left.
        /// </value>
        [Description("The left clip"), Category("Camera")]
        public double Left
        {
            get { return left; }
            set
            {
                if (left != value)
                {
                    left = value;

                    NotifyPropertyChanged("Left");
                }
            }
        }

        /// <summary>
        /// Gets or sets the right.
        /// </summary>
        /// <value>
        /// The right.
        /// </value>
        [Description("The right clip"), Category("Camera")]
        public double Right
        {
            get { return right; }
            set
            {
                if (right != value)
                {
                    right = value;

                    NotifyPropertyChanged("Right");
                }
            }
        }

        /// <summary>
        /// Gets or sets the top.
        /// </summary>
        /// <value>
        /// The top.
        /// </value>
        [Description("The top clip"), Category("Camera")]
        public double Top
        {
            get { return top; }
            set
            {
                if (top != value)
                {
                    top = value;

                    NotifyPropertyChanged("Top");
                }
            }
        }

        /// <summary>
        /// Gets or sets the bottom.
        /// </summary>
        /// <value>
        /// The bottom.
        /// </value>
        [Description("The bottom clip"), Category("Camera")]
        public double Bottom
        {
            get { return bottom; }
            set
            {
                if (bottom != value)
                {
                    bottom = value;

                    NotifyPropertyChanged("Bottom");
                }
            }
        }

        /// <summary>
        /// Gets or sets the near.
        /// </summary>
        /// <value>
        /// The near.
        /// </value>
        [Description("The near clip"), Category("Camera")]
        public double Near
        {
            get { return near; }
            set
            {
                if (near != value)
                {
                    near = value;

                    NotifyPropertyChanged("Near");
                }
            }
        }

        /// <summary>
        /// Gets or sets the far.
        /// </summary>
        /// <value>
        /// The far.
        /// </value>
        [Description("The far clip"), Category("Camera")]
        public double Far
        {
            get { return far; }
            set
            {
                if (far != value)
                {
                    far = value;

                    NotifyPropertyChanged("Far");
                }
            }
        }

        #endregion Public Properties
    }
}
